/**
 * 
 */
package cz.cuni.mff.abacs.burglar.logics.objects.agents;

import java.util.ArrayList;
import java.util.List;


/**
 * Goalset to protect an area.
 * 
 * @author abacs
 *
 */
public class GuardGoal implements GoalBase {
	
	
	/** Rooms not yet visited. */
	protected final List<Integer> _roomsToVisit = 
			new ArrayList<Integer>();
	
	/** Rooms that need to be visited only in the next loop. */
	protected final List<Integer> _roomsAlreadyVisited = 
			new ArrayList<Integer>();
	
	
	/** A vender that the agent needs to visit. */
	protected int _venderToVisit = -1;
	
	
	
	// -------------------------------------------------------------------------
	// constructors:
	
	
	/**
	 * 
	 * 
	 * @param roomsToVisit
	 */
	public GuardGoal(List<Integer> roomsToVisit) {
		for(Integer roomId : roomsToVisit)
			this._roomsToVisit.add(roomId);
	}
	
	
	/**
	 * 
	 * @param other
	 */
	protected GuardGoal(GuardGoal other) {
		for(Integer roomId : other._roomsToVisit)
			this._roomsToVisit.add(roomId);
		for(Integer roomId : other._roomsAlreadyVisited)
			this._roomsAlreadyVisited.add(roomId);
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/**
	 * Adds a new room to protect.
	 */
	public void addAimId(int roomId) {
		if(
			this._roomsAlreadyVisited.contains(roomId) ||
			this._roomsToVisit.contains(roomId)
		){
			return;
		}
		this._roomsToVisit.add(roomId);
	}	
	
	
	/**
	 * Marks the given room as already visited.
	 * 
	 * @param roomId
	 */
	public void setRoomVisited(int roomId) {
		if(this._roomsToVisit.contains(roomId) == false)
			return;
		
		this._roomsToVisit.remove(this._roomsToVisit.indexOf(roomId));
		this._roomsAlreadyVisited.add(roomId);
		
		// if the agent has to move between multiple rooms and there
		// are no more unvisited rooms in this loop, mark all of them unvisited.
		if(
			this._roomsToVisit.isEmpty() &&
			this._roomsAlreadyVisited.size() > 1
		){
			this.markAllUnvisited();
			this.setRoomVisited(roomId);
		}
	}
	
	
	/**
	 * Marks all rooms as unvisited.
	 */
	public void markAllUnvisited() {
		while(this._roomsAlreadyVisited.isEmpty() == false){
			this._roomsToVisit.add(this._roomsAlreadyVisited.remove(0));
		}
	}
	
	
	/** 
	 * Not yet visited rooms that the guard has to plan with.
	 * 
	 * @return the rooms that are not yet visited in the current walking cycle.
	 */
	public List<Integer> getRoomsToVisit() {
		return new ArrayList<Integer>(this._roomsToVisit);
	}
	
	
	/** 
	 * Returns all the rooms the guard had to visit in the past or the future.
	 * 
	 * @return
	 */
	public List<Integer> getAllGoalRooms() {
		List<Integer> ret = new ArrayList<Integer>();
		ret.addAll(this._roomsToVisit);
		ret.addAll(this._roomsAlreadyVisited);
		return ret;
	}
	
	
	/**
	 * Checks the room's visited status.
	 */
	public boolean isRoomVisited(int roomId) {
		return this._roomsAlreadyVisited.contains(roomId);
	}
	
	
	/**
	 * Checks the room's visited status.
	 */
	public boolean isRoomToVisit(int roomId) {
		return this._roomsToVisit.contains(roomId);
	}
	
	
	// -------------------------------------------------------------------------
	
	
	@Override
	public void setVenderIdToVisit(int venderToVisit) {
		this._venderToVisit = venderToVisit;
	}
	
	
	@Override
	public void removeVenderToVisit() {
		this._venderToVisit = -1;
	}
	
	
	@Override
	public boolean hasVenderToVisit() {
		return this._venderToVisit != -1;
	}
	
	
	@Override
	public int getVenderIdToVisit() {
		return this._venderToVisit;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/* (non-Javadoc)
	 * @see cz.cuni.mff.abacs.burglar.logics.objects.agents.GoalBase#isSatisfied(cz.cuni.mff.abacs.burglar.logics.objects.agents.BaseAgent)
	 */
	@Override
	public boolean isSatisfied(BaseAgent agent) {
		return false;
	}
	
	
	// -------------------------------------------------------------------------
	
	
	/* (non-Javadoc)
	 * @see cz.cuni.mff.abacs.burglar.logics.objects.agents.GoalBase#copyChangeables(cz.cuni.mff.abacs.burglar.logics.objects.agents.GoalBase)
	 */
	@Override
	public void copyChangeables(GoalBase other) {
		
		GuardGoal other_ = (GuardGoal)other;
		
		this._roomsToVisit.clear();
		for(Integer roomId : other_._roomsToVisit)
			this._roomsToVisit.add(roomId);
		
		this._roomsAlreadyVisited.clear();
		for(Integer roomId : other_._roomsAlreadyVisited)
			this._roomsAlreadyVisited.add(roomId);
	}
	
	
}
